﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using IGolovkine.Core.Diagnostics;
using IGolovkine.Core;

namespace IGolovkine.ShoutCastRipper.Testing.ConnectionRecorder
{
    public class XmlStationClientEventWriter : IStationClientEventWriter
    {
        private XmlTextWriter _writer;

        private readonly TypeFactory<XmlTextWriter> _writerFactory;
        private readonly ObjectDisposedCheck _disposedCheck;
        private const string DateTimeFormat = "dd-MMM-yyyy HH:mm:ss.ffff";

        public XmlStationClientEventWriter(TypeFactory<XmlTextWriter> writerFactory)
        {
            Debug.NotDefault(() => writerFactory);
            _writerFactory = writerFactory;
            _disposedCheck = new ObjectDisposedCheck(this);
        }

        private DateTime _startTime;
        private void Initialise()
        {
            if (_writer == null)
            {
                _writer = _writerFactory();
                _writer.Formatting = Formatting.Indented;
                _writer.WriteStartDocument();
                _writer.WriteStartElement("Recording");
                _startTime = DateTime.Now;
                _writer.WriteAttributeString("Time", _startTime.ToString(DateTimeFormat));
            }
            else
            {
                throw new InvalidOperationException(string.Format("{0} is already initialised", _writer.GetType().Name));
            }
        }

        private void EnsureInitialised()
        {
            if (_writer == null)
            {
                this.Initialise();
            }
        }

        public void WriteDisconnectedEvent(DisconnectedEventArgs e)
        {
            this.WriteStartElement(e);
            _writer.WriteAttributeString("ContentLength", e.ContentLength.ToString());
            if (e.Exception != null)
            {
                _writer.WriteStartElement("Exception");
                _writer.WriteAttributeString("AssemblyQualifiedName", e.Exception.GetType().AssemblyQualifiedName);
                _writer.WriteAttributeString("Message", e.Exception.Message);
                _writer.WriteEndElement();
            }
            _writer.WriteEndElement();
            _writer.Flush();
        }

        public void WriteContentStartEvent(ContentStartEventArgs e)
        {
            this.WriteStartElement(e);
            _writer.WriteEndElement();
            _writer.Flush();
        }

        public void WriteContentReceivedEvent(ContentReceivedEventArgs e)
        {
            this.WriteStartElement(e);
            _writer.WriteAttributeString("ContentLength", e.ContentLength.ToString());
            _writer.WriteAttributeString("DataLength", e.Data.Length.ToString());
            _writer.WriteEndElement();
            _writer.Flush();
        }

        public void WriteContentEndEvent(ContentEndEventArgs e)
        {
            this.WriteStartElement(e);
            _writer.WriteAttributeString("ContentLength", e.ContentLength.ToString());
            _writer.WriteEndElement();
            _writer.Flush();
        }

        private void WriteStartElement(StationClientEvent e)
        {
            this.EnsureInitialised();
            _writer.WriteStartElement("Event");
            _writer.WriteAttributeString("Type", e.GetType().Name);
            _writer.WriteAttributeString("TimeElapsed", (DateTime.Now - _startTime).ToString());
            if (e.ContentTitle != null)
            {
                _writer.WriteAttributeString("ContentTitle", e.ContentTitle);
            }
        }


        public void Dispose()
        {
            _disposedCheck.Dispose();
            _writer.WriteEndElement();
            _writer.WriteEndDocument();
            _writer.Close();
        }
    }
}
